package sf.database.support;

import sf.core.DBField;
import sf.database.dbinfo.ColumnInfo;
import sf.database.meta.ColumnMapping;
import sf.database.meta.TableMapping;

import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 表结构变更时，整个操作过程进度的事件监听器(可以干涉修改表的过程)
 *
 * <ol>
 * 按事件的时间顺序如下
 * <li>{@linkplain #beforeTableRefresh(TableMapping, String) 变更表之前 （可以控制是否继续刷新操作）} </li>
 * <li>{@linkplain #onTableCreate(TableMapping, String) 如果表不存在，创建表之前（可以控制是否建表）}</li>
 * <li>{@linkplain #onCompareColumns(String, List, Map) 如果表存在，在比较表之前（可以控制是否继续刷新操作）}</li>
 * <li>{@linkplain #onColumnsCompared(String, TableMapping, Set, List, List) 数据库中的表和元数据比较完成后}</li>
 * <li>{@linkplain #beforeAlterTable(String, TableMapping, Connection, List) 比较完成并生成SQL后，在操作表之前}</li>
 * <li>{@linkplain #onAlterSqlFinished(String, String, List, int, long) 在每句SQL执行成功后}</li>
 * <li>{@linkplain #onSqlExecuteError(Exception, String, String, List, int) 在任何一句SQL执行失败后}</li>
 * <li>{@linkplain #onTableFinished(TableMapping, String) 在所有SQL都执行完成后}</li>
 * </ol>
 * @author
 */
public interface MetadataEventListener {
    /**
     * 当开始变更一张表时执行
     * @param meta  表的元数据
     * @param table 数据库中的表名
     * @return false，则放弃变更此表
     */
    default boolean beforeTableRefresh(TableMapping meta, String table) {
        return false;
    }

    /**
     * 表不存在，将会创建表
     * @param meta      表的元数据
     * @param tablename 数据库中的表名
     * @return false，则放弃创建此表
     */
    default boolean onTableCreate(TableMapping meta, String tablename) {
        return false;
    }

    /**
     * 表结构比较完成后出发，提供了表的对比结果供用户判断。<br>
     * 在这个方法中，实现类可以直接修改传入的比较结果，让后续的程序按修改后的比较结果执行ALTER TABLE语句。
     * @param tablename 表名
     * @param meta      表的元数据
     * @param insert    将要增加的数据库列(列名、数据类型)
     * @param changed   数据格式发生了变更的列
     * @param delete    将要删除的列
     * @return false则放弃变更此表
     */
    default boolean onColumnsCompared(String tablename, TableMapping meta, Set<ColumnMapping> insert, List<ColumnMapping> changed, List<String> delete) {
        return false;
    }

    /**
     * 框架根据表对比结果，生成SQL语句后触发此事件，用户事件中可以获得所有的SQL语句。
     * @param tablename 表名
     * @param meta      元数据
     * @param conn      数据库连接
     * @param sql       所有的SQL语句
     */
    default void beforeAlterTable(String tablename, TableMapping meta, Connection conn, List<String> sql) {

    }

    /**
     * 每一句SQL语句执行完成后
     * @param tablename 表名
     * @param sql       刚完成的SQL语句
     * @param sqls      所有SQL语句
     * @param n         序号，第几句SQL，编号从0开始
     * @param cost      刚才的SQL语句耗时(ms)
     */
    default void onAlterSqlFinished(String tablename, String sql, List<String> sqls, int n, long cost) {

    }

    /**
     * 当某句SQL语句执行失败后触发
     * @param e         异常
     * @param tablename 表名
     * @param sql       出错的SQL语句
     * @param sqls      所有SQL语句
     * @param n         出错的SQL语句序号
     * @return 如果返回true，表示继续执行后续的语句，如果返回false表示不再向后执行
     */
    default boolean onSqlExecuteError(Exception e, String tablename, String sql, List<String> sqls, int n) {
        return false;
    }

    /**
     * 表变更完成
     * @param meta      表元数据
     * @param tablename 表名
     */
    default void onTableFinished(TableMapping meta, String tablename) {

    }

    /**
     * 开始进行表结构的比较
     * @param tablename 表名
     * @param columns   数据库中的所有列
     * @param defined   表模型中的所有列
     * @return 是否继续比较这张表
     */
    default boolean onCompareColumns(String tablename, List<ColumnInfo> columns, Map<DBField, ColumnMapping> defined) {
        return true;
    }
}
